/**
 * SpringAdvisable.java
 * 
 * Created on Jul 10, 2008 at 12:41:24 AM
 */
package org.lego4j.internal;

import org.lego4j.IValidableAdvisor;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.ProxyConfig;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.AopUtils;

/**
 * TODO add javadoc to SpringAdvisable
 *
 * @author <a href="alexguev@gmail.com">Alexei Guevara</>
 * @version $Revision:$ updated on $Date:$ by $Author:$
 */
public class SpringAdvisable implements IAdvisable {

    private final Object myBean;
    private final Class<?> myBeanClass;
    private final ProxyConfig myProxyConfig;
    private final ClassLoader myBeanClassLoader;
    
    private IAddAdvicePolicy myAddAdvicePolicy;
    
    private Object myAdvisedBean;
    

    public SpringAdvisable(Object theBean, Class<?> theBeanClass, ProxyConfig theProxyConfig, ClassLoader theBeanClassLoader ) {
        myBean = theBean; 
        myBeanClass = theBeanClass;
        myProxyConfig = theProxyConfig;
        myBeanClassLoader = theBeanClassLoader;
        
        myAddAdvicePolicy = findOutAddAdvicePolicyAndUpdateAdvisedBean();
    }

    private IAddAdvicePolicy findOutAddAdvicePolicyAndUpdateAdvisedBean() {
        if (myBean instanceof Advised) {
            myAdvisedBean = myBean;
            return BeanIsAlreadyAdvicedAddAdvicePolicy.INSTANCE;
        }
        else {
            ProxyFactory proxyFactory = new ProxyFactory(myBean);
            // Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
            proxyFactory.copyFrom( myProxyConfig );
            myAdvisedBean = proxyFactory.getProxy( myBeanClassLoader );

            return new ProxyFactoryAddAdvicePolicy( proxyFactory );
        }
    }

    /**
     * {@inheritDoc}
     */
    public boolean canApply(IValidableAdvisor theAdvisor) {
        return AopUtils.canApply( theAdvisor, myBeanClass );
    }
    
    /**
     * {@inheritDoc}
     */
    public void addAdvisor(IValidableAdvisor theAdvisor) {
        theAdvisor.validate( myBeanClass );
        myAddAdvicePolicy.doAddAdvisor( myBean, theAdvisor );
    }

    /**
     * {@inheritDoc}
     */
    public Object getAdvicedBean() {
        return myAdvisedBean;
    }

}
